<script setup lang="ts">
import MapboxMap from '@/components/mapbox-map/MapboxMap.vue'
import mapboxgl, { LngLat } from 'mapbox-gl'
import MapboxDraw from '@mapbox/mapbox-gl-draw'
import { ref, reactive, watch, nextTick } from 'vue'
import * as coordtransform from 'coordtransform'
import { getCoords, polygon, lineString } from '@turf/turf'
import styles from '@/utils/draw-style/styles.js'
import { nanoid } from 'nanoid'
import { jsonp } from '@/utils/jsonp'
import LocationInfoPopup from '@/components/draw-map/location-info-popup.vue'
import { remove } from 'lodash'
import { Message } from 'element-ui'

const props = defineProps({
  visible: { type: Boolean, default: false },
  title: { type: String, default: '' },
  data: { type: Object, default: () => ({}) },
  mapId: { type: String, default: 'one-map-draw' },
  mapType: { type: String, default: 'draw' },
  disabled: { type: Boolean, default: false },
  type: { type: String, default: '' },
})

const emit = defineEmits(['update', 'close'])

const fetchBaseMapListDone = ref(true)

const baseMapConfig = reactive({
  type: 'vector',
  name: '矢量',
  id: 'vector',
})

let _map: mapboxgl.Map | null = null
let draw: MapboxDraw | null = null

const isDrawPoint = ref(false)

interface PopupInfoStruct {
  id: string
  popup: mapboxgl.Popup
  marker: mapboxgl.Marker
  point: number[]
  address: string
}
let markers: PopupInfoStruct[] = []

const MAP_KEY = 'FQWBZ-PJXEU-LRZV2-BUBN5-AFKGO-R6BKQ'

const resizeMap = (_map: mapboxgl.Map) => {
  _map.resize()
}

const deleteMarker = (id: string) => {
  const item = markers.find((m) => m.id === id)
  if (item) {
    item.marker.remove()
    item.popup.remove()
    remove(markers, item)
  }
}

const addMarker = async (lngLat: LngLat, addressStr = '') => {
  if (!_map) return
  const lng = Number(lngLat.lng.toFixed(6))
  const lat = Number(lngLat.lat.toFixed(6))
  const [l1, l2] = coordtransform.wgs84togcj02(lng, lat)
  const url = `https://apis.map.qq.com/ws/geocoder/v1/?location=${l2},${l1}&key=${MAP_KEY}&get_poi=0`
  let address = addressStr
  const id = nanoid()
  if (!addressStr) {
    try {
      // 添加延迟避免并发请求冲突
      await new Promise(resolve => setTimeout(resolve, Math.random() * 100))
      const res: any = await jsonp(url, { output: 'jsonp' })
      if (res.status === 0) {
        address = res.result?.formatted_addresses?.recommend || `位置 ${lng.toFixed(4)},${lat.toFixed(4)}`
      } else {
        address = `位置 ${lng.toFixed(4)},${lat.toFixed(4)}`
      }
    } catch (e) {
      address = `位置 ${lng.toFixed(4)},${lat.toFixed(4)}`
    }
  }

  const Constructor = (await import('vue')).default.extend(LocationInfoPopup)
  const popupInstance = new Constructor({
    propsData: {
      pointInfo: [lng, lat],
      address,
      id,
      deleteMarker,
      disabled: props.disabled,
    },
  }).$mount()

  const popup = new mapboxgl.Popup({
    anchor: 'bottom',
    closeOnClick: false,
    closeButton: false,
    offset: [0, -10],
    className: 'marker',
    maxWidth: '120px',
  }).setDOMContent(popupInstance.$el)

  popup.setLngLat(lngLat).addTo(_map)

  const el = document.createElement('div')
  const center = document.createElement('div')
  center.style.width = '16px'
  center.style.height = '16px'
  center.style.backgroundColor = '#00BAFF'
  center.style.borderRadius = '50%'
  center.style.border = '2px solid white'
  el.style.width = '84px'
  el.style.height = '84px'
  el.style.background = 'rgba(0,186,255,.2)'
  el.style.borderRadius = '50%'
  el.style.display = 'flex'
  el.style.justifyContent = 'center'
  el.style.alignItems = 'center'
  el.appendChild(center)

  const marker = new mapboxgl.Marker(el).setLngLat(lngLat).addTo(_map)

  markers.push({
    id,
    popup,
    marker,
    point: [lng, lat],
    address,
  })
}

const afterMapLoaded = (mapId: string, map: mapboxgl.Map) => {
  _map = map

  draw = new MapboxDraw({
    keybindings: false,
    touchEnabled: false,
    boxSelect: false,
    displayControlsDefault: false,
    styles,
  })

  _map.addControl(draw)

  _map.on('draw.create', () => {
    isDrawPoint.value = false
  })

  _map.on('click', (event) => {
    if (isDrawPoint.value) {
      isDrawPoint.value = false
      addMarker(event.lngLat)
    }
  })

  resizeMap(_map)

  if (props.visible) {
    handleOpen()
  }
}

watch(
  () => props.data.communityId,
  (val) => {
    if (!val && _map?.getLayer('line-area')) {
      _map.removeLayer('line-area')
      _map.removeSource('line-area')
    }
  }
)

watch(
  () => props.visible,
  (visible) => {
    if (visible && _map) {
      handleOpen()
      nextTick(() => {
        resizeMap(_map!)
      })
    }
  }
)

const onClear = () => {
  const ids = draw?.getSelectedIds()
  if (ids && ids.length === 1) {
    draw?.delete(ids)
  } else if (ids && ids.length > 1) {
    Message.warning('请只选中一个要素进行删除')
  } else {
    Message.warning('请先选中要删除的要素')
  }
}

const addDraw = (type: 'polyline' | 'polygon' | 'point') => {
  isDrawPoint.value = type === 'point'

  switch (type) {
    case 'polyline':
      draw?.changeMode('draw_line_string')
      break
    case 'polygon':
      draw?.changeMode('draw_polygon')
      break
    case 'point':
      draw?.changeMode('simple_select')
      break
  }
}

const clearAll = () => {
  draw?.deleteAll()
  markers.forEach((m) => {
    m.marker.remove()
    m.popup.remove()
  })
  markers = []
}

const beforeMapDestroyed = () => {
  clearAll()
}

const onSave = () => {
  const obj = {
    pointPosition: '',
    pointWgsPosition: '',
    lineWgsPosition: '',
    linePosition: '',
    wgsPosition: '',
    position: '',
  }

  if (draw) {
    draw.changeMode('simple_select')
    const data = draw.getAll()
    const { features } = data
    const polygonArr: any[] = []
    const polylineArr: any[] = []
    const pointArr: any[] = []

    features.forEach((fea) => {
      if (fea.geometry.type === 'LineString') {
        const coords = getCoords(fea as any)
        polylineArr.push(coords)
      } else if (fea.geometry.type === 'Polygon') {
        const coords = getCoords(fea as any)
        polygonArr.push(coords[0])
      } else if (fea.geometry.type === 'Point') {
        const coords = getCoords(fea as any)
        pointArr.push(coords)
      }
    })

    if (polygonArr.length) {
      const polygonArr2 = polygonArr.map((polygon) =>
        polygon.map((point: any) => coordtransform.wgs84togcj02(point[0], point[1]))
      )
      obj.wgsPosition = JSON.stringify(polygonArr)
      obj.position = JSON.stringify(polygonArr2)
    } else {
      obj.wgsPosition = ''
      obj.position = ''
    }

    if (polylineArr.length) {
      const polylineArr2 = polylineArr.map((polyline) =>
        polyline.map((point: any) => coordtransform.wgs84togcj02(point[0], point[1]))
      )
      obj.lineWgsPosition = JSON.stringify(polylineArr)
      obj.linePosition = JSON.stringify(polylineArr2)
    } else {
      obj.lineWgsPosition = ''
      obj.linePosition = ''
    }

    if (pointArr.length) {
      const pointArr2 = pointArr.map((point: any) => coordtransform.wgs84togcj02(point[0], point[1]))
      // 如果没有markers，使用绘制的点数据
      if (!markers || markers.length === 0) {
        obj.pointWgsPosition = JSON.stringify(pointArr.map((p) => [...p, '']))
        obj.pointPosition = JSON.stringify(pointArr2.map((p) => [...p, '']))
      }
    }
  }

  // 标记点数据和绘制的点统一保存
  if (markers && markers.length) {
    const points = markers.map((item) => [...item.point, item.address])
    const wgsPoints = markers.map((item) => [...coordtransform.wgs84togcj02(item.point[0], item.point[1]), item.address])
    obj.pointWgsPosition = JSON.stringify(points)
    obj.pointPosition = JSON.stringify(wgsPoints)
  } else if (!obj.pointWgsPosition) {
    obj.pointWgsPosition = ''
    obj.pointPosition = ''
  }

  emit('update', obj)
}

const handleClose = () => {
  emit('close')
  if (_map) {
    draw?.changeMode('simple_select')
    clearAll()
    if (_map.getLayer('line-area')) {
      _map.removeLayer('line-area')
      _map.removeSource('line-area')
    }
  }
}

const handleOpen = () => {
  if (!draw || !_map) return
  if (props.mapType !== 'draw') return

  const { geoJsonData, wgsPosition, lineWgsPosition, pointWgsPosition } = props.data || {}
  if (geoJsonData) {
    try {
      // 这里支持传入字符串或对象，且支持FeatureCollection和Feature数组
      const geoJson = typeof geoJsonData === 'string' ? JSON.parse(geoJsonData) : geoJsonData
      if (geoJson) {
        if (geoJson.type === 'FeatureCollection' && Array.isArray(geoJson.features)) {
          geoJson.features.forEach((feature: any) => {
            draw?.add(feature)
          })
        } else if (geoJson.type === 'Feature') {
          draw?.add(geoJson)
        }
      }
    } catch (e) {
      console.warn('Failed to parse GeoJSON data:', geoJsonData)
    }
  }

  // 兼容旧格式面数据
  if (wgsPosition) {
    const polygons = JSON.parse(wgsPosition)
    if (Array.isArray(polygons)) {
      polygons.forEach((points: any) => {
        const poly = polygon([points])
        draw?.add(poly)
      })
    }
  }

  // 兼容旧格式线数据
  if (lineWgsPosition) {
    const lines = JSON.parse(lineWgsPosition)
    if (Array.isArray(lines)) {
      lines.forEach((points: any) => {
        const line = lineString(points)
        draw?.add(line)
      })
    }
  }

  // 兼容旧格式点数据，标记点形式
  if (pointWgsPosition) {
    const points = JSON.parse(pointWgsPosition)
    points.forEach((point: any, index: number) => {
      const lngLat = new LngLat(point[0], point[1])
      // 如果没有地址信息，使用默认地址避免 JSONP 请求冲突
      const address = point[2] || `点位${index + 1}`
      addMarker(lngLat, address)
    })
  }

  draw.changeMode('simple_select')
  resizeMap(_map)
}
</script>

<template>
  <div
    v-show="visible"
    class="draw-map-backdrop"
    @click.self="handleClose"
  >
    <div class="draw-map-container">
      <div class="draw-map-header" v-if="title">
        <div class="title">{{ title }}</div>
        <div class="close-btn" @click="handleClose">
          <span>×</span>
        </div>
      </div>

      <div class="choice-position-map-div">
        <div class="buttons" v-if="mapType === 'draw' && !disabled">
          <el-button @click="addDraw('polyline')" v-if="type === '8'">绘制线</el-button>
          <el-button @click="addDraw('polygon')" v-if="type === '10'">绘制面</el-button>
          <el-button @click="addDraw('point')" v-if="type === '24'">增加点</el-button>
          <el-button @click="onClear" v-if="['8','10','24'].includes(type)">清除绘制</el-button>
          <el-button @click="clearAll" v-if="['8','10','24'].includes(type)">清除全部</el-button>
        </div>
        <div class="choice-map-container">
          <MapboxMap
            :map-id="mapId"
            v-if="fetchBaseMapListDone && visible"
            :base-map-config="baseMapConfig"
            @after-map-loaded="afterMapLoaded"
            @before-map-destroyed="beforeMapDestroyed"
          />
        </div>
      </div>

      <div class="dialog-footer" v-if="mapType === 'draw' && !disabled">
        <el-button type="primary" @click="onSave">保存</el-button>
        <el-button @click="handleClose">取消</el-button>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.draw-map-backdrop {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: rgba(0,0,0,0.5);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: all;
}
.draw-map-container {
  width: 70%;
  max-width: 1200px;
  height: 80vh;
  max-height: 700px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.15);
  display: flex;
  flex-direction: column;
  pointer-events: all;
}
.draw-map-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid #e8e8e8;
  background: #f8f9fa;
  border-radius: 8px 8px 0 0;
  pointer-events: all;
}
.draw-map-header .title {
  font-size: 16px;
  font-weight: 600;
  color: #333;
}
.draw-map-header .close-btn {
  cursor: pointer;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #f0f0f0;
  color: #666;
  font-size: 18px;
  font-weight: bold;
  transition: background-color 0.2s;
  pointer-events: all;
}
.draw-map-header .close-btn:hover {
  background: #e0e0e0;
}
.choice-position-map-div {
  flex: 1;
  position: relative;
  overflow: hidden;
  pointer-events: all;
}
.buttons {
  position: absolute;
  top: 22px;
  left: 18px;
  z-index: 1000;
  pointer-events: all;
}
.buttons .el-button {
  margin-right: 8px;
  margin-bottom: 8px;
  pointer-events: all;
}
.choice-map-container {
  height: 100%;
  width: 100%;
  pointer-events: all;
}
.choice-map-container .mapbox-map {
  width: 100%;
  height: 100%;
  pointer-events: all;
}
.dialog-footer {
  display: flex;
  justify-content: center;
  gap: 12px;
  padding: 16px 20px;
  border-top: 1px solid #e8e8e8;
  background: #f8f9fa;
  border-radius: 0 0 8px 8px;
  pointer-events: all;
}
</style>
